QuickOPC User's Guide and Reference
Working with data types
Extensions > Integrated Extensions > OPC UA Complex Data Extension > Generic data and data types > Working with data types
In This Topic

A data type is represented by an instance of some type derived from the DataType Class. The DataType Class itself is abstract, but there are several concrete classes that derive from it.

Data types can be of several different kinds: enumeration, opaque, primitive, sequence, or structured. Refer to Data type kinds for mode details on the individual kinds. You can determine the kind of data type you are dealing with either by testing it actual type, or using its Kind Property.

Refer to Creating data types if you need to create an instance of some data type (derived from the DataType Class; that is actually rare, maybe just for generic data validation purposes - see Generic data validation). If you need to process a data type object that you have obtained from the comonent, refer to Processing data types.

Recursive data types

The data type is recursive when it contains a cycle, directly or indirectly. For example, a structured data type may contain a field that is a sequence of the same data type. Recursive data types as such are not invalid, and are even not so uncommon; for example, the Variant data type is defined recursively. You can determine whether the data type is recursive using its IsRecursive Property.

For the data type to be usable, however, it must be terminable. The data type is terminable if it is capable of producing finite data. All non-recursive data types are terminable, but not all recursive types are. For example, in the example with a structured data type above, the data type would be terminable if the field was optional, or if the length of the sequence was not fixed (and could be zero). In such cases the expansion of the data type can be stopped at some point, by omitting the field form the data, or having a zero length sequence. If, however, the field was mandatory and the sequence had a fixed non-zero length, such data type would not be terminable - and would be basically useless, because the only data it can describe is infinite.

You can determine whether a data type is terminable using its IsTerminable Property.

Incomplete types

The data type is complete when all its constituent data type are filled in are are themselves complete. For example, the field in the structured data type must have their types defined by a non-null data type.

Normally, when data types are constructed, you create them already as complete. But in order construct recursive data types, an incomplete data type needs to be created first, and the loop - the missing data type - is closed later.  Incomplete data types should therefore exist only temporarily, during their construction. They must not participate in further operations, and generic data is invalid for operations when it has an incomplete data type associated with it - see Generic data validation.

You can determine whether a data type is complete using its IsComplete Property.

Displaying data types

When you invoke the ToString Method on some data type, or view it in the debugger, you will get a short, on-line rendering of the data type. It contains its name (if it has a name), its kind (such as 'structured' or 'enumerable'), and possibly some details specific to the data type kind (such as the .NET type associated with primitive data). You may get, for example:

(ScalarValueDataType) structured

If you want to see the information about the internals of the data type, you can use the "V" (verbose) format specifier. For example, this code (C#):

Console.WriteLine("{0:V}", dataType); 

may produce following output (truncated):

    ScalarValueDataType = structured
      [BooleanValue] Boolean = primitive(System.Boolean)
      [ByteStringValue] ByteString = primitive(System.Byte[])
      [ByteValue] Byte = primitive(System.Byte)
      [DateTimeValue] DateTime = primitive(System.DateTime)
      [DoubleValue] Double = primitive(System.Double)
      [EnumerationValue] Int32 = primitive(System.Int32)
      [ExpandedNodeIdValue] ExpandedNodeId = structured
        [ByteString] optional ByteStringNodeId = structured
        [Identifier] ByteString = primitive(System.Byte[])
          [NamespaceIndex] UInt16 = primitive(System.UInt16)
        [FourByte] optional FourByteNodeId = structured
          [Identifier] UInt16 = primitive(System.UInt16)
          [NamespaceIndex] Byte = primitive(System.Byte)
        [Guid] optional GuidNodeId = structured
          [Identifier] Guid = primitive(System.Guid)
          [NamespaceIndex] UInt16 = primitive(System.UInt16)
        [NamespaceURI] optional CharArray = primitive(System.String)
        [NamespaceURISpecified] switch Bit = primitive(System.Boolean)
        [NodeIdType] switch NodeIdType = enumeration(6)
          TwoByte = 0
          FourByte = 1
          Numeric = 2
          String = 3
          Guid = 4
          ByteString = 5
        [Numeric] optional NumericNodeId = structured
          [Identifier] UInt32 = primitive(System.UInt32)
          [NamespaceIndex] UInt16 = primitive(System.UInt16)
        [ServerIndex] optional UInt32 = primitive(System.UInt32)
        [ServerIndexSpecified] switch Bit = primitive(System.Boolean)
        [String] optional StringNodeId = structured
          [Identifier] CharArray = primitive(System.String)
          [NamespaceIndex] UInt16 = primitive(System.UInt16)
        [TwoByte] optional TwoByteNodeId = structured
        [Identifier] Byte = primitive(System.Byte)
      [FloatValue] Float = primitive(System.Single)
      [GuidValue] Guid = primitive(System.Guid)
      [Int16Value] Int16 = primitive(System.Int16)
      [Int32Value] Int32 = primitive(System.Int32)
      [Int64Value] Int64 = primitive(System.Int64)
      [Integer] Variant = structured
        [ArrayDimensions] optional sequence[*] of Int32 = primitive(System.Int32)
        [ArrayDimensionsSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
        [ArrayLength] length optional Int32 = primitive(System.Int32)
        [ArrayLengthSpecified] switch sequence[1] of Bit = primitive(System.Boolean)
        [Boolean] optional sequence[*] of Boolean = primitive(System.Boolean)
        [Byte] optional sequence[*] of Byte = primitive(System.Byte)

The component will correctly (without looping infinitely) display recursive data types as well.

If you want to see the internals of the data type in debugger, you can, of course, inspect its properties, sub-properties and so on. That can be quite a tedious task. For a quick overview, you can view the data type in the same format as with the "V" (verbose) format specifier. To do so, find the DebugView property of the data type, and display its contents (possibly using the Text Visualizer in Visual Studio debugger). Note that the DebugView property is private, and therefore is not listed in the reference documentation for the component.

See Also

Reference